//
//  FXEventType.swift
//  FXEvent
//
//  Created by Fanxx on 2021/11/23.
//

import Foundation

/// 事件
public protocol FXEventType {
    /// 参数类型，无参可使用Void
    associatedtype ParameterType
    /// 开关
    var isEnabled: Bool { get set }
    /// 添加事件处理
    func addTarget(_ target: AnyObject, action: Selector)
    /// 移除事件处理
    func removeTarget(_ target: AnyObject, action: Selector)
    /// 移除事件处理
    func removeTarget(_ target: AnyObject)
    /// 添加事件处理
    func addBlock(_ identifier: String, block: @escaping (ParameterType) -> Void)
    /// 添加事件处理
    func addBlock(_ block: @escaping (ParameterType) -> Void)
    /// 移除事件处理
    func removeBlock(_ identifier: String)
    /// 移除全部事件处理
    func removeAllActions()
    /// 触发事件
    func sendActions(for parameter: ParameterType)
}
/// 无参数事件
extension FXEventType where ParameterType == Void {
    /// 添加事件处理
    public func addBlock(_ identifier: String, block: @escaping () -> Void) {
        self.addBlock(identifier) { _ in
            block()
        }
    }
    /// 添加事件处理
    public func addBlock(_ block: @escaping () -> Void) {
        self.addBlock { _ in
            block()
        }
    }
    /// 触发事件
    public func sendActions() {
        self.sendActions(for: ())
    }
}
/// 可空参数事件
extension FXEventType where ParameterType: ExpressibleByNilLiteral {
    /// 触发事件
    public func sendActions() {
        self.sendActions(for: nil)
    }
}
extension FXEventType where Self: AnyObject {
    /// 绑定到另一个事件，当该事件触发时根据值来决定要不要激活当前事件
    public func when<OtherEventType: FXEventType>(_ otherEvent: OtherEventType, where predicate: @escaping (OtherEventType.ParameterType) -> Bool, identifier: String = "\(#file):\(#function):\(#line)", _ block: @escaping (ParameterType) -> Void) {
        otherEvent.addBlock { [weak self] otherParameter in
            self?.removeBlock(identifier)
            if predicate(otherParameter) {
                self?.addBlock(identifier, block: block)
            }
        }
    }
    /// 绑定到另一个事件，当该事件触发时根据值来决定要不要激活当前事件
    public func when<OtherEventType: FXEventType>(_ otherEvent: OtherEventType, where states: OtherEventType.ParameterType..., identifier: String = "\(#file):\(#function):\(#line)", _ block: @escaping (ParameterType) -> Void) where OtherEventType.ParameterType: Equatable {
        self.when(otherEvent, where: { states.contains($0) }, identifier: identifier, block)
    }
    /// 绑定到另一个事件，当该事件触发时根据值来决定要不要激活当前事件
    public func when<OtherEventType: FXEventType>(_ otherEvent: OtherEventType, identifier: String = "\(#file):\(#function):\(#line)", _ block: @escaping (ParameterType) -> Void) where OtherEventType.ParameterType == Bool {
        self.when(otherEvent, where: { $0 }, identifier: identifier, block)
    }
}
